from ctypes import *

from app import utils

logMgr = utils.logMgr


class USBI2C():
    ch341 = windll.LoadLibrary("CH341DLL")
    dev_addr_start = 0x00
    dev_addr_end = 0xff

    def __init__(self, usb_dev=0, i2c_dev=0x5c, commfreq=0x82, callback=None):
        logMgr.print('USBI2C init')
        self.usb_id = usb_dev
        self.dev_addr = i2c_dev
        self.usb_init = False  # usb
        self.dev_connected = False  # iic
        self.iic_callback = callback
        self.commfreq=commfreq

        self.initUSB()
    def onNotify(self,s):
        print("onNotify:"+str(s))

    def initUSB(self):
        if USBI2C.ch341.CH341OpenDevice(self.usb_id) != -1:
            # rou=CH341.mPCH341_NOTIFY_ROUTINE()
            ver=USBI2C.ch341.CH341GetVersion()
            print("ch341 version:"+str(ver))
            callback1 = CFUNCTYPE(c_int, c_int)
            cb = callback1(callbackfunc1)
            # USBI2C.ch341.CH341SetDeviceNotify(self.usb_id,"1",cb)

            USBI2C.ch341.CH341SetStream(self.usb_id, self.commfreq)
            USBI2C.ch341.CH341CloseDevice(self.usb_id)
            logMgr.print('USB CH341 init Ok!')
            self.usb_init = True
            if self.iic_callback is not None:
                self.iic_callback.onUSBConnectd()
                self.iic_callback.onStateOutput(msg="USB CH341 init Ok!")
        else:
            logMgr.print("USB CH341 init Failed!")
            self.usb_init = False
            self.dev_connected = False
            if self.iic_callback is not None:
                self.iic_callback.onUSBClosed()
                self.iic_callback.onStateOutput(level="e", msg="USB CH341 init Failed!")

    def setCallback(self, callback):
        self.iic_callback = callback

    def set_usb_freq(self, commfreq):
        logMgr.print('set_usb_freq')
        if USBI2C.ch341.CH341OpenDevice(self.usb_id) != -1:
            USBI2C.ch341.CH341SetStream(self.usb_id, commfreq)
            USBI2C.ch341.CH341CloseDevice(self.usb_id)
            if self.iic_callback is not None:
                self.iic_callback.onUSBConnectd()
                self.iic_callback.onStateOutput(msg="set_usb_freq Ok:" + str(commfreq))
            logMgr.print('set_usb_freq Ok:')

    def get_s16(self, val):  # c语言有符号数转为python有符号数
        if val < 0x8000:
            return val
        else:
            return (val - 0x10000)

    def read(self, addr, cnt=1):
        if USBI2C.ch341.CH341OpenDevice(self.usb_id) != -1:
            ibuf = (c_byte * cnt)()
            if addr != None:
                obufl = [self.dev_addr, addr]
            else:
                obufl = [self.dev_addr]
            datacnt = len(obufl)
            obuf = (c_byte * datacnt)()
            for x in range(datacnt):
                obuf[x] = obufl[x] & 0xff
            # print('write', [hex(x) for x in obufl], datacnt)
            # CH341StreamI2C
            # 1：ch341设备id
            # 2、写数据字节数
            # 3、写数据缓冲区，首字节是设备地址
            # 4、读取字节数
            # 5、读取缓冲区
            USBI2C.ch341.CH341StreamI2C(self.usb_id, datacnt, obuf, cnt, ibuf)
            USBI2C.ch341.CH341CloseDevice(self.usb_id)
            logMgr.print("read","addr:"+str(hex(addr)),"-->"+utils.bytes2Hex(ibuf))
            if len(ibuf) == 1:
                return ibuf[0] & 0xff
            else:
                res = []
                for x in range(len(ibuf)):
                    res.append(ibuf[x] & 0xff)
                return res
        else:
            logMgr.print("USB CH341 Open Failed!")
            self.usb_init = False
            self.dev_connected = False
            if self.iic_callback is not None:
                self.iic_callback.onStateOutput(level="e", msg="Read Fail,USB CH341 Open Failed!")
            return 0


    #
    # 读连续字节，返回格式化的hex列表
    #
    def readReg(self, addr, cntbyte, datatypelen=2, hasStateByte=False):
        if USBI2C.ch341.CH341OpenDevice(self.usb_id) != -1:
            obuf = (c_byte * 2)()
            ibuf = (c_byte * cntbyte)()
            obuf[0] = self.dev_addr  # 从机地址
            obuf[1] = addr  # 目标寄存器地址

            # CH341StreamI2C
            # 1：ch341设备id
            # 2、写数据字节数
            # 3、写数据缓冲区，首字节是设备地址
            # 4、读取字节数
            # 5、读取缓冲区
            USBI2C.ch341.CH341StreamI2C(self.usb_id, 2, obuf, cntbyte, ibuf)
            USBI2C.ch341.CH341CloseDevice(self.usb_id)
            # print(type(ibuf),len(ibuf))
            logMgr.print("read","addr:"+str(hex(addr)),"-->"+utils.bytes2Hex(ibuf))
            return self.analyseData(ibuf, datatypelen, hasStateByte=hasStateByte)
        else:
            self.usb_init = False
            self.dev_connected = False
            logMgr.print("USB CH341 Open Failed!")
            if self.iic_callback is not None:
                self.iic_callback.onStateOutput(level="e", msg="Read Fail,USB CH341 Open Failed!")
            return 0
    #
    # 写入单字节
    #
    def write(self, addr, dat):
        if USBI2C.ch341.CH341OpenDevice(self.usb_id) != -1:
            obuf = (c_byte * 3)()
            ibuf = (c_byte * 1)()
            obuf[0] = self.dev_addr
            obuf[1] = addr
            obuf[2] = dat & 0xff
            logMgr.print('write ',"addr:"+str(hex(addr))+"-->",[hex(x) for x in obuf],len(obuf))
            USBI2C.ch341.CH341StreamI2C(self.usb_id, 3, obuf, 0, ibuf)
            USBI2C.ch341.CH341CloseDevice(self.usb_id)
            return ibuf
        else:
            self.usb_init = False
            self.dev_connected = False
            if self.iic_callback is not None:
                self.iic_callback.onStateOutput(level="e", msg="Write Fail,USB CH341 Open Failed!")
            logMgr.print("USB CH341 Open Failed!")


    #
    # 写入多字节
    #
    def writeArr(self, addr=None, dat=0):
        if USBI2C.ch341.CH341OpenDevice(self.usb_id) != -1:
            # print('write',addr,dat)
            ibuf = (c_byte * 1)()
            obufl = []
            if addr != None:
                obufl = [self.dev_addr, addr]
            else:
                obufl = [self.dev_addr]
            if type(dat) == list:
                obufl += dat
            else:
                obufl.append(dat)
            datacnt = len(obufl)
            obuf = (c_byte * datacnt)()
            for x in range(datacnt):
                obuf[x] = obufl[x] & 0xff
            logMgr.print('write',"addr:"+str(hex(addr))+"-->",[hex(x) for x in obufl],datacnt)
            USBI2C.ch341.CH341StreamI2C(self.usb_id, datacnt, obuf, 0, ibuf)
            USBI2C.ch341.CH341CloseDevice(self.usb_id)
            return ibuf
        else:
            self.usb_init = False
            self.dev_connected = False
            print("USB CH341 Open Failed!")

    def analyseData(self, ibuf, datatypelen, hasStateByte=False):
        res = []
        tmpl = []
        tmp = 0
        cnttmp = 0
        offset = 0
        if hasStateByte:
            offset = 1
        # logMgr.print("read",utils.bytes2Hex(ibuf))
        for x in range(len(ibuf)):
            if x < offset:
                res.append(ibuf[x] & 0xff)  # 状态位
            else:
                tmpl.append(ibuf[x] & 0xff)  # 数据
        # print(tmpl)
        for x in range(len(tmpl)):
            cnttmp += 1
            idx = x % datatypelen
            tmp += (tmpl[x] << idx * 8)
            if cnttmp % datatypelen == 0:
                tmp = self.get_s16(tmp)
                res.append(tmp)
                tmp = 0
        return res

    def setdev_addr(self, addr):
        # print('setdev_addr ',addr)
        self.dev_addr = addr


def callbackfunc1(eventid):
    print('eventid ',eventid)
    return eventid


